home *** CD-ROM | disk | FTP | other *** search
- /*
- * IP.C
- * IP level routines, including ICMP
- * also includes a basic version of UDP, not generalized yet
- *
- ****************************************************************************
- * *
- * part of: *
- * TCP/IP kernel for NCSA Telnet *
- * by Tim Krauskopf *
- * *
- * National Center for Supercomputing Applications *
- * 152 Computing Applications Building *
- * 605 E. Springfield Ave. *
- * Champaign, IL 61820 *
- * *
- * Copyright (c) 1987, Board of Trustees of the University of Illinois *
- * *
- ****************************************************************************
- * Revision history:
- *
- * 10/87 Initial source release, Tim Krauskopf
- * 2/88 typedefs of integer lengths, TK
- */
-
- #include <stdio.h>
- #include <String.h>
- #include "protocol.h"
- #include "data.h"
- #include "tools.h"
- #include "mactools.h"
- #include "tcp.h"
-
- extern unsigned char SLIP_ip_number[]; /* BYU 2.4.15 */
-
- extern uint16 ipcheck
- (
- void *buf,
- long wdcnt /* BYU 2.4.8 - was "int" */
- );
-
- extern uint16 tcpcheck
- (
- void *phd,
- void *buf,
- long btcnt /* BYU 2.4.8 - was "int" */
- );
-
- /****************************************************************************/
- /* udpinterpret
- * take incoming UDP packets and make them available to the user level
- * routines. Currently keeps the last packet coming in to a port.
- *
- * Limitations:
- * Can only listen to one UDP port at a time. Only saves the last packet
- * received on that port.
- * Port numbers should be assigned like TCP ports are (future).
- */
- int udpinterpret
- (
- UDPKT *p,
- int ulen
- )
- {
- uint hischeck,mycheck;
- /*
- * did we want this data ? If not, then let it go, no comment
- * If we want it, copy the relevent information into our structure
- */
- if (intswap(p->u.dest) != ulist.listen)
- return(1);
-
- /*
- * first compute the checksum to see if it is a valid packet
- */
- hischeck = p->u.check;
- p->u.check = 0;
-
- if (hischeck) {
- movebytes(tcps.source,p->i.ipsource,8);
- tcps.z = 0;
- tcps.proto = p->i.protocol;
-
- tcps.tcplen = intswap(ulen);
-
-
- mycheck = tcpcheck(&tcps,&p->u,ulen);
-
- if (hischeck != mycheck) {
- netposterr(700);
- return(2);
- }
-
- p->u.check = hischeck; /* put it back */
- }
-
- ulen -= 8; /* account for header */
- if (ulen > UMAXLEN) /* most data that we can accept */
- ulen = UMAXLEN;
-
- movebytes(ulist.who,p->i.ipsource,4);
- movebytes(ulist.data,p->data,ulen);
- ulist.length = ulen;
- ulist.stale = 0;
- netputuev(USERCLASS,UDPDATA,ulist.listen); /* post that it is here */
-
- return(0);
- } /* udpinterpret */
-
- /***************************************************************************/
- /* neticmpturn
- *
- * send out an icmp packet, probably in response to a ping operation
- * interchanges the source and destination addresses of the packet,
- * puts in my addresses for the source and sends it
- *
- * does not change any of the ICMP fields, just the IP and dlayers
- * returns 0 on okay send, nonzero on error
- */
-
- int neticmpturn
- (
- ICMPKT *p,
- int ilen, /* BYU 2.4.15 */
- short fromSLIP /* BYU 2.4.15 */
- )
- {
- unsigned char *pc;
- /*
- * reverse the addresses, dlayer and IP layer
- */
- if (!fromSLIP) { /* BYU 2.4.15 */
- if (comparen(p->d.me,broadaddr,DADDLEN)) /* BYU 2.4.15 */
- return(0); /* BYU 2.4.15 */
-
- movebytes(p->d.dest,p->d.me,DADDLEN); /* BYU 2.4.15 */
-
- #ifdef MAC
- /*
- * look up address in the arp cache if we are using AppleTalk
- * encapsulation.
- */
- if (!nnemac) { /* BYU 2.4.15 */
- pc = getdlayer(p->i.ipsource); /* BYU 2.4.15 */
- if (pc != NULL) /* BYU 2.4.15 */
- movebytes(p->d.dest,pc,DADDLEN); /* BYU 2.4.15 */
- else /* BYU 2.4.15 */
- return(0); /* no hope this time */ /* BYU 2.4.15 */
- } /* BYU 2.4.15 */
- #endif
- } /* BYU 2.4.15 */
-
-
- movebytes(p->i.ipdest,p->i.ipsource,4);
-
- if (fromSLIP) /* BYU 2.4.15 */
- movebytes(p->i.ipsource,SLIP_ip_number,4); /* BYU 2.4.15 */
- else { /* BYU 2.4.15 */
- movebytes(p->d.me,nnmyaddr,DADDLEN); /* BYU 2.4.15 */
- movebytes(p->i.ipsource,nnipnum,4); /* BYU 2.4.15 */
- } /* BYU 2.4.15 */
-
- /*
- * prepare ICMP checksum
- */
- p->c.check = 0;
- p->c.check = ipcheck(&p->c,ilen>>1);
-
- /*
- * iplayer for send
- */
- p->i.ident = intswap(nnipident++);
- p->i.check = 0;
- p->i.check = ipcheck(&p->i,10);
-
- /*
- * send it
- */
- return(dlayersend(p,sizeof(DLAYER)+sizeof(IPLAYER)+ilen,fromSLIP)); /* BYU 2.4.15 */
-
- } /* neticmpturn */
-
- /****************************************************************************/
- /* icmpinterpret
- * interpret the icmp message that just came in
- */
- int icmpinterpret
- (
- ICMPKT *p,
- int icmplen, /* BYU 2.4.15 */
- short fromSLIP /* BYU 2.4.15 */
- )
- {
- uint i,hisck;
- IPLAYER *iptr;
-
- i = p->c.type;
- netposterr(600 + i); /* provide info for higher layer user */
-
- #ifdef oldway
- hisck = p->c.check;
- p->c.check = 0;
- #else
- #pragma unused(hisck)
- #endif
-
- if (p->c.check) { /* ignore if chksum = 0 */
- if (ipcheck(&p->c,icmplen>>1)) {
- netposterr(699);
- return(-1);
- }
- }
-
- switch (i) {
- case 8: /* ping request sent to me */
- p->c.type = 0; /* echo reply type */
- neticmpturn(p,icmplen,fromSLIP); /* BYU 2.4.15 - send back */
- break;
-
- case 5: /* ICMP redirect */
- iptr = (IPLAYER *)p->data;
- netputuev(ICMPCLASS,IREDIR,0); /* event to be picked up */
-
- movebytes(nnicmpsave,iptr->ipdest,4); /* dest address */
- movebytes(nnicmpnew,&p->c.part1,4); /* new gateway */
- break;
-
- default:
- break;
- }
-
- return(0);
- } /* icmpinterpret */
-
- /***************************************************************************/
- /* ipinterpret
- * Called by the reception routine with a new IP packet. Check the checksum,
- * addressing and protocol type and call appropriate routines.
- */
-
- int ipinterpret
- (
- IPKT *p, /* BYU 2.4.15 */
- short fromSLIP /* BYU 2.4.15 */
- )
- {
- int iplen,i;
-
- /*
- * We cannot handle fragmented IP packets yet, return an error
- */
- if (p->i.frags & 0x20) {
- netposterr(304);
- return(1);
- }
-
- /*
- * checksum verification of IP header
- */
-
- if (p->i.check) { /* no IP checksumming if check=0 */
- if (ipcheck(&p->i.versionandhdrlen,(p->i.versionandhdrlen & 0x0f) << 1)) {
- netposterr(300); /* bad IP checksum */
- return(1); /* drop packet */
- }
- }
-
- /*
- * check to make sure that the packet is for me.
- * Throws out all packets which are not directed to my IP address.
- *
- * This code is incomplete. It does not pass broadcast IP addresses up
- * to higher layers. It used to report packets which were incorrectly
- * addressed, but no longer does. Needs proper check for broadcast
- * addresses.
- */
- if (fromSLIP) { /* BYU 2.4.15 */
- if (!comparen(SLIP_ip_number,p->i.ipdest,4))/* BYU 2.4.15 - potential non-match */
- return(1); /* BYU 2.4.15 - drop packet */
- } else { /* BYU 2.4.15 */
- if (!comparen(nnipnum,p->i.ipdest,4)) /* BYU 2.4.15 - potential non-match */
- return(1); /* BYU 2.4.15 - drop packet */
- } /* BYU 2.4.15 */
- /*
- * Extract total length of packet
- */
- iplen = intswap(p->i.tlen);
-
- /*
- * See if there are any IP options to be handled.
- * We don't understand IP options, post a warning to the user and drop
- * the packet.
- */
- i = (p->i.versionandhdrlen & 0x0f)<<2;
-
- if (i > 20) {
- netposterr(302); /* packet with options */
- return(1);
- }
-
- switch (p->i.protocol) { /* which protocol to handle this packet? */
- case PROTUDP:
- return(udpinterpret((UDPKT *) p,iplen-i));
- case PROTTCP:
- return(tcpinterpret((TCPKT *) p,iplen-i,fromSLIP)); /* BYU 2.4.15 - pass tcplen on to TCP */
- case PROTICMP:
- return(icmpinterpret((ICMPKT *) p,iplen-i,fromSLIP)); /* BYU 2.4.15 */
- default:
- netposterr(303);
- return(1);
- }
-
- return(0);
- } /* ipinterpret */
-
- #ifdef NNDEBUG
- ipdump(p)
- IPKT *p;
- {
- uint16 iplen,iid;
-
- iid = intswap(p->i.ident);
-
- iplen = intswap(p->i.tlen);
-
- puts("found IP packet:");
-
- printf("Version+hdr: %x service %d tlen %u \015", /* BYU 2.4.18 - changed \n to \015 */
- p->i.versionandhdrlen,p->i.service,iplen);
- printf("Ident: %u frags: %4x ttl: %d prot: %d \015", /* BYU 2.4.18 - changed \n to \015 */
- iid,p->i.frags,p->i.ttl,p->i.protocol);
- printf("addresses: s: %d.%d.%d.%d t: %d.%d.%d.%d \015", /* BYU 2.4.18 - changed \n to \015 */
- p->i.ipsource[0],p->i.ipsource[1],p->i.ipsource[2],p->i.ipsource[3],
- p->i.ipdest[0],p->i.ipdest[1],p->i.ipdest[2],p->i.ipdest[3]);
-
-
- puts("\015"); /* BYU 2.4.18 - changed \n to \015 */
-
- }
-
- /***************************************************************************/
- /* ipsend THIS ROUTINE HAS NOT BEEN TESTED, NEVER USED!
- *
- * generic send of an IP packet according to parameters. Use of this
- * procedure is discouraged. Terribly inefficient, but may be useful for
- * tricky or diagnostic situations. Unused for TCP.
- *
- * usage: ipsend(data,ident,prot,options,hdrlen)
- * data is a pointer to the data to be sent
- * ident is the 16 bit identifier
- * prot is the protocol type, PROTUDP or PROTTCP or other
- * hlen is in bytes, total header length, 20 is minimum
- * dlen is the length of the data field, in bytes
- * who is ip address of recipient
- * options must be included in hlen and hidden in the data stream
- */
- ipsend(data,dlen,iid,iprot,who,hlen)
- unsigned char *data,iprot,*who;
- int iid,dlen,hlen;
- {
- int iplen;
-
- if (dlen > 512)
- dlen = 512;
-
- iplen = hlen+dlen; /* total length of packet */
- blankip.i.tlen = intswap(iplen); /* byte swap */
-
- blankip.i.versionandhdrlen = 0x40 | (hlen>>2);
-
- blankip.i.ident = intswap(iid); /* byte swap */
-
- blankip.i.protocol = iprot;
-
- blankip.i.check = 0; /* set to 0 before calculating */
-
- movebytes(blankip.i.ipdest,who,4);
- movebytes(blankip.d.me,myaddr,DADDLEN);
-
- movenbytes(blankip.x.data,data,dlen); /* might be header options data */
-
- blankip.i.check = ipcheck(&blankip.i.versionandhdrlen,hlen>>1);
- /* checks based on words */
-
-
- /* resolve knowledge of Ethernet hardware addresses */
-
- /*
- * This is commented out because I know that this procedure is broken!
- * If you use it, debug it first.
-
- dlayersend(&blankip,iplen+14,0); /* BYU 2.4.15 */
- */
-
- return(0);
- } /* ipsend */
-
- #endif
-
- /****************************************************************************/
- /* neturead
- * get the data from the UDP buffer
- * Returns the number of bytes transferred into your buffer, -1 if none here
- * This needs work.
- */
- int neturead
- (
- char *buffer
- )
- {
- if (ulist.stale)
- return(-1);
-
- movebytes(buffer,ulist.data,ulist.length);
- ulist.stale = 1;
-
- return(ulist.length);
- } /* neturead */
-
- /***************************************************************************/
- /* netulisten
- * Specify which UDP port number to listen to.
- * Can only listen to one at a time.
- */
- void netulisten
- (
- int port
- )
- {
- ulist.listen = port;
- }
-
- /***************************************************************************/
- /* netusend
- * send some data out in a UDP packet
- * uses the preinitialized data in the port packet ulist.udpout
- *
- * returns 0 on okay send, nonzero on error
- */
- int netusend
- (
- unsigned char *machine,
- unsigned int port,
- unsigned int retport,
- unsigned char *buffer,
- int n
- )
- {
- unsigned char *pc;
-
- if (n > UMAXLEN)
- n = UMAXLEN;
- /*
- * make sure that we have the right dlayer address
- */
- if (!comparen(machine,ulist.udpout.i.ipdest,4)) {
- pc = netdlayer(machine);
- if (pc == NULL)
- return(-2);
- movebytes(ulist.udpout.d.dest,pc,DADDLEN);
- movebytes(ulist.udpout.i.ipdest,machine,4);
- movebytes(ulist.tcps.dest,machine,4);
- }
-
- ulist.udpout.u.dest = intswap(port);
- ulist.udpout.u.source = intswap(retport);
- ulist.tcps.tcplen = ulist.udpout.u.length = intswap(n+sizeof(UDPLAYER));
- movenbytes(ulist.udpout.data,buffer,n);
-
- /*
- * put in checksum
- */
- ulist.udpout.u.check = 0;
- ulist.udpout.u.check = tcpcheck(&ulist.tcps,&ulist.udpout.u,n+sizeof(UDPLAYER));
-
- /*
- * iplayer for send
- */
- ulist.udpout.i.tlen = intswap(n+sizeof(IPLAYER)+sizeof(UDPLAYER));
- ulist.udpout.i.ident = intswap(nnipident++);
- ulist.udpout.i.check = 0;
- ulist.udpout.i.check = ipcheck(&ulist.udpout.i,10);
- /*
- * send it
- */
- return(dlayersend(&ulist.udpout,
- sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(UDPLAYER)+n,0)); /* BYU 2.4.15 */
- } /* netusend */
-
- #ifdef notneeded
- /***************************************************************************/
- /* neticmpsend
- * Not currently used. Has not been tested since 9/87.
- * Do not assume this works (TK)
- *
- * send out an icmp packet, probably to do a ping operation
- *
- * returns 0 on okay send, nonzero on error
- */
- neticmpsend(machine,type,code,buffer,n)
- unsigned char *machine,*buffer,type,code;
- int n;
- {
- unsigned char *pc;
-
- if (n > ICMPMAX)
- n = ICMPMAX;
- /*
- * make sure that we have the right dlayer address
- *
- * this may be re-entrant, needs checking. Okay, as long as this compare
- * is false when called from netsleep() routines!
- * When called from user routines, we are okay.
- */
- if (!comparen(machine,blankicmp.i.ipdest,4)) {
- pc = netdlayer(machine);
- if (pc == NULL)
- return(-2);
- movebytes(blankicmp.d.dest,pc,DADDLEN);
- movebytes(blankicmp.i.ipdest,machine,4);
- /* movebytes(ulist.tcps.dest,machine,4); */
- }
- /*
- * prepare ICMP portion
- */
- blankicmp.c.type = type;
- blankicmp.c.code = code;
- movenbytes(&blankicmp.data,buffer,n);
-
- blankicmp.c.check = 0;
- blankicmp.c.check = ipcheck(&blankicmp.c,(sizeof(ICMPLAYER)+n)>>1);
-
- /*
- * iplayer for send
- */
- blankicmp.i.tlen = intswap(n+sizeof(IPLAYER)+sizeof(ICMPLAYER));
- blankicmp.i.ident = intswap(nnipident++);
- blankicmp.i.check = 0;
- blankicmp.i.check = ipcheck(&blankicmp.i,10);
- /*
- * send it
- */
- return(dlayersend(&blankicmp,
- sizeof(DLAYER)+sizeof(IPLAYER)+sizeof(ICMPLAYER)+n,0)); /* BYU 2.4.15 */
-
- }
- #endif
-